home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / Bitmap Libraries 2.0 / BitMap.c next >
Text File  |  1996-07-08  |  15KB  |  533 lines

  1. /* File BitMap.c Copyright (C) 1996 by John R. Montbriand.  All Rights Reserved. */
  2.  
  3. /* File BitMap.c
  4.  
  5.     Copyright (C) 1996 by John Montbriand.  All Rights Reserved.
  6.     
  7.     Distribute freely in areas where the laws of copyright apply.
  8.     
  9.     Use at your own risk.
  10.     
  11.     Do not distribute modified copies.
  12.     
  13.     These various BitMap libraries are for free!
  14.     
  15.     See the accompanying file BitMap.txt for details.
  16.     
  17. */
  18.  
  19. #include "BitMap.h"
  20. #include <Memory.h>
  21. #include <ToolUtils.h>
  22. #include <OSUtils.h>
  23. #include <FixMath.h>
  24. #include <Math.h>
  25.  
  26. #pragma segment BitMaps
  27.  
  28.  
  29. BitMap* NewBitMap(short width, short height) {
  30.     short rowBytes;
  31.     long bytes;
  32.     BitMap *bits;
  33.     rowBytes = ((width + 15) >> 4) << 1;
  34.     bytes = sizeof(BitMap) + ((long) rowBytes) * ((long) height);
  35.     if ((bits = (BitMap*) NewPtrClear(bytes)) == NULL) return NULL;
  36.     bits->baseAddr =  ((char*) bits) + sizeof(BitMap);
  37.     bits->rowBytes = rowBytes;
  38.     bits->bounds.left = bits->bounds.top = 0;
  39.     bits->bounds.right = width;
  40.     bits->bounds.bottom = height;
  41.     return bits;
  42. }
  43.  
  44. void KillBitMap(BitMap* bits) {
  45.     DisposePtr((Ptr) bits);
  46. }
  47.  
  48.  
  49. /* SafeHeightNewBitMap is an internal routine for creating bitmaps
  50.     appropriately sized for the left and right rotation routines.  */
  51. static BitMap* SafeHeightNewBitMap(short width, short height) {
  52.     short safeheight;
  53.     BitMap* bits;
  54.     safeheight = (((height + 15) >> 4) << 1) * 8;
  55.     if ((bits = NewBitMap(width, safeheight)) != NULL) bits->bounds.bottom = height;
  56.     return bits;
  57. }
  58.  
  59. /* ShiftLeftWords is an internal routine called to shift bits to the
  60.     left after horizontal flip operations and right rotations.  Sometimes
  61.     this is required as bitmaps are rotated using the memory
  62.     storage conventions rather than the coordinate mapping conventions.  */
  63. static void ShiftLeftWords(void* p, long words, short nshifts) {
  64.     long i, j;
  65.     unsigned short* wp;
  66.     for (j=0;j<nshifts;j++) for (wp = (unsigned short*) p, i=0; i<words; i++) {
  67.         wp[i] <<= 1;
  68.         if (i+1 < words && (wp[i+1] & 0x8000) != 0) wp[i] |= 1;
  69.     }
  70. }
  71.  
  72. BitMap* RotateRight(BitMap* bits) {
  73.     short sWidth, sHeight;
  74.     BitMap *result, *src, *dst;
  75.     unsigned char *sp,  bit, *dp, *dbyt, sbyt, mask;
  76.     register long x, y, i;
  77.     sWidth = bits->bounds.right - bits->bounds.left;
  78.     sHeight = bits->bounds.bottom - bits->bounds.top;
  79.     if ((result = SafeHeightNewBitMap(sHeight, sWidth)) != NULL) {
  80.         src = bits;
  81.         dst = result;
  82.         sp = (unsigned char*) src->baseAddr;
  83.         bit = 0x01;
  84.         dp = ((unsigned char*) dst->baseAddr) + dst->rowBytes - 1;
  85.         for (y = 0; y < src->bounds.bottom; y++) {        // for every row...
  86.             for (dbyt = dp, x=0; x < src->rowBytes; x++)    // scan the row...
  87.                 for(sbyt = *sp++, mask = 0x80, i=0;i<8;i++, mask >>= 1, dbyt += dst->rowBytes)
  88.                     if (sbyt & mask) *dbyt |= bit;
  89.             if (bit == 0x80) { bit = 0x01; dp--; } else bit <<= 1;
  90.         }
  91.         x = dst->rowBytes*8 - dst->bounds.right;
  92.         dp = (unsigned char*) dst->baseAddr;
  93.         for (i = 0; i < dst->bounds.bottom; i++, dp += dst->rowBytes)
  94.             ShiftLeftWords(dp, dst->rowBytes/2, x);
  95.     }
  96.     return result;
  97. }
  98.  
  99. BitMap* RotateLeft(BitMap* bits) {
  100.     short sWidth, sHeight;
  101.     BitMap *result, *src, *dst;
  102.     register long x, y, i;
  103.     unsigned char *sp, bit, *dp, *dbyt, sbyt, mask;
  104.     sWidth = bits->bounds.right - bits->bounds.left;
  105.     sHeight = bits->bounds.bottom - bits->bounds.top;
  106.     if ((result = SafeHeightNewBitMap(sHeight, sWidth)) != NULL) {
  107.         src = bits;
  108.         dst = result;
  109.         sp = (unsigned char*) src->baseAddr;
  110.         bit = 0x80;
  111.         dp = ((unsigned char*) dst->baseAddr) + (dst->rowBytes * (dst->bounds.bottom-1));
  112.         for (y = 0; y < src->bounds.bottom; y++) {        // for every row...
  113.             for (dbyt = dp, x=0; x < src->rowBytes; x++)    // scan the row...
  114.                 for(sbyt = *sp++, mask = 0x80, i=0;i<8;i++, mask >>= 1, dbyt -= dst->rowBytes)
  115.                     if (sbyt & mask) *dbyt |= bit;
  116.             if (bit == 0x01) { bit = 0x80; dp++; } else bit >>= 1;
  117.         }
  118.     }
  119.     return result;
  120. }
  121.  
  122. BitMap* FlipVertical(BitMap* bits) {
  123.     BitMap *result, *src, *dst;
  124.     register long v;
  125.     unsigned char *sp, *dp;
  126.     if ((result = DuplicateBitMap(bits)) != NULL) {
  127.         src = bits;
  128.         dst = result;
  129.         sp = (unsigned char*) src->baseAddr;
  130.         dp = ((unsigned char*) dst->baseAddr) + (dst->bounds.bottom-1)*(long)dst->rowBytes;
  131.         for (v = 0; v < src->bounds.bottom; v++) {
  132.             BlockMoveData(sp, dp, dst->rowBytes);
  133.             sp += src->rowBytes;
  134.             dp -= dst->rowBytes;
  135.         }
  136.         return result;
  137.     }
  138.     return NULL;
  139. }
  140.  
  141. BitMap* FlipHorizontal(BitMap* bits) {
  142.     BitMap *result, *src, *dst;
  143.     register long h, v, i;
  144.     unsigned char *sp, *dp, *s, *d, mask, bit, sByte;
  145.     result = bits;
  146.     if ((result = DuplicateBitMap(bits)) != NULL) {
  147.         src = bits;
  148.         dst = result;
  149.         sp = (unsigned char*) src->baseAddr;
  150.         dp = (unsigned char*) dst->baseAddr;
  151.         for (v = 0; v < src->bounds.bottom; v++) {
  152.             for (s = sp + src->rowBytes, d = dp, h = 0; h < src->rowBytes; h++, d++)
  153.                 for (mask=0x01, bit=0x80, sByte = *--s, *d=0,i=0; i<8; i++, mask<<=1, bit>>=1)
  154.                     if (sByte & mask) *d |= bit;
  155.             sp += src->rowBytes;
  156.             ShiftLeftWords(dp, dst->rowBytes / 2, dst->rowBytes*8 - dst->bounds.right);
  157.             dp += dst->rowBytes;
  158.         }
  159.         return result;
  160.     }
  161.     return NULL;
  162. }
  163.  
  164.  
  165. /* There are two implementations of the RotateBitMap routine: one for
  166.     the 68000, and another for the PowerPC.  Fixed point math is faster
  167.     than floating point on the 68000, however floating point is faster
  168.     than fixed point on the PowerPC.   The method we use maps pixels that
  169.     are set in the source bitmap to their appropriate position in the
  170.     destination performing the necessary calculations only if the pixel is
  171.     equal to 1.  I have heard that better image quality can be found by
  172.     mapping from the destination to the source, but I was more interested
  173.     in speed when I made this.  */
  174.  
  175. #if defined(powerc) || defined(__powerc)
  176.  
  177. short myround(float x) {
  178.         float low, high;
  179.         low = floor(x);
  180.         high = ceil(x);
  181.         if (fabs(low - x) < fabs(high - x))
  182.             return (short) low;
  183.         else return (short) high;
  184. }
  185.  
  186. BitMap* RotateBitMap(BitMap* bits, short cx, short cy, float angle) {
  187.     BitMap *result, *src, *dst;
  188.     register long h, v, i;
  189.     unsigned char *sp, *dp, *s, *d, bit;
  190.     float x, y, rad, crad, srad, zx, zy, ccx, ccy;
  191.     short xx, yy;
  192.     Point pt;
  193.     if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
  194.         src = bits;
  195.         rad = -(0.017453 * angle);
  196.         crad = cos(rad);
  197.         srad = sin(rad);
  198.         ccx = (float) cx;
  199.         ccy = (float) cy;
  200.         sp = (unsigned char*) src->baseAddr;
  201.         for (v = 0; v < src->bounds.bottom; v++, sp += src->rowBytes)
  202.             for (s = sp, h = 0; h < src->rowBytes; h++, s++)
  203.                 for (bit=0x80, i=0; i<8; i++, bit>>=1)
  204.                     if (((*s) & bit) != 0) {
  205.                         zx = ((float) (h*8+i)) - ccx;
  206.                         zy =((float) v) - ccy;
  207.                         xx = myround(zx*crad + zy*srad + ccx);
  208.                         if (xx >= src->bounds.left && xx < src->bounds.right) {
  209.                             yy = myround(zy*crad - zx*srad + ccy);
  210.                             if (yy >= src->bounds.top && yy < src->bounds.bottom)
  211.                                 BitMapSet(result, xx, yy);
  212.                         }
  213.                     }
  214.         return result;
  215.     }
  216.     return NULL;
  217. }
  218.  
  219. #else
  220.  
  221. BitMap* RotateBitMap(BitMap* bits, short cx, short cy, float angle) {
  222.     BitMap *result, *src, *dst;
  223.     register long h, v, i;
  224.     unsigned char *sp, *dp, *s, *d, bit;
  225.     Fixed x, y, rad, crad, srad, zx, zy, ccx, ccy;
  226.     short xx, yy;
  227.     Point pt;
  228.     if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
  229.         src = bits;
  230.         rad = FixMul(0x00000478, -X2Fix(angle));
  231.         crad = FracCos(rad);
  232.         srad = FracSin(rad);
  233.         ccx = FixRatio(cx, 1);
  234.         ccy = FixRatio(cy, 1);
  235.         sp = (unsigned char*) src->baseAddr;
  236.         for (v = 0; v < src->bounds.bottom; v++, sp += src->rowBytes)
  237.             for (s = sp, h = 0; h < src->rowBytes; h++, s++)
  238.                 for (bit=0x80, i=0; i<8; i++, bit>>=1)
  239.                     if (((*s) & bit) != 0) {
  240.                         zx = FixRatio((h*8+i), 1) - ccx;
  241.                         zy =FixRatio (v, 1) - ccy;
  242.                         xx = FixRound(FracMul(zx, crad) + FracMul(zy, srad) + ccx);
  243.                         if (xx >= src->bounds.left && xx < src->bounds.right) {
  244.                             yy = FixRound(FracMul(zy, crad) - FracMul(zx, srad) + ccy);
  245.                             if (yy >= src->bounds.top && yy < src->bounds.bottom)
  246.                                 BitMapSet(result, xx, yy);
  247.                         }
  248.                     }
  249.         return result;
  250.     }
  251.     return NULL;
  252. }
  253.  
  254. #endif
  255.  
  256. BitMap* iRotateBitMap(BitMap* bits, short cx, short cy, short angle) {
  257.         return RotateBitMap(bits, cx, cy, (float) angle);
  258. }
  259.  
  260.  
  261. BitMap* DuplicateBitMap(BitMap* bits) {
  262.     BitMap *result;
  263.     long bytes;
  264.     result = bits;
  265.     result = NewBitMap(bits->bounds.right, bits->bounds.bottom);
  266.     if (result != NULL) {
  267.         BlockMoveData(bits, result,
  268.             sizeof(BitMap) + ((long) result->rowBytes) * ((long) result->bounds.bottom));
  269.         result->baseAddr =  ((char*) result) + sizeof(BitMap);
  270.         return result;
  271.     } else return NULL;
  272. }
  273.  
  274. BitMap* PaintBucketBitMap(BitMap* bits, short h, short v) {
  275.     BitMap *result, *src, *dst;
  276.     if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
  277.         src = bits;
  278.         dst = result;
  279.         SeedFill(src->baseAddr, dst->baseAddr, src->rowBytes, dst->rowBytes,
  280.             dst->bounds.bottom, dst->rowBytes/2, h, v);
  281.     }
  282.     return result;
  283. }
  284.  
  285. BitMap* LassoBitMap(BitMap* bits) {
  286.     BitMap *result, *src, *dst;
  287.     if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
  288.         src = bits;
  289.         dst = result;
  290.         CalcMask(src->baseAddr, dst->baseAddr, src->rowBytes, dst->rowBytes,
  291.             dst->bounds.bottom, dst->rowBytes/2);
  292.     }
  293.     return result;
  294. }
  295.  
  296. BitMap* TraceBitMap(BitMap* bits) {
  297.     BitMap *the_edges;
  298.     if ((the_edges = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
  299.         BitMapPort* bmp;
  300.         WithBitMap(the_edges, bmp) {
  301.             PlotBitMap(bits, -1, -1, srcOr);
  302.             PlotBitMap(bits, 1, -1, srcOr);
  303.             PlotBitMap(bits, -1, 1, srcOr);
  304.             PlotBitMap(bits, 1, 1, srcOr);
  305.             PlotBitMap(bits, 0, 0, srcBic);
  306.         }
  307.     }
  308.     return the_edges;
  309. }
  310.  
  311. /* EqualBitMaps takes into account that the rowbytes in the differing images may be
  312.     different and that bits off to the right of the image may contain garbage. */
  313. Boolean EqualBitMaps(BitMap* a, BitMap* b) {
  314.     unsigned char *aptr, *bptr, *arover, *brover;
  315.     long x, y, bytecount, extrabits, mask;
  316.     
  317.         /* something not there? */
  318.     if (a == NULL || b == NULL) return false;
  319.     
  320.         /* different boundary rectangles? */
  321.     if (!EqualRect(&a->bounds, &b->bounds)) return false;
  322.     
  323.         /* different image content? */
  324.     aptr = (unsigned char*) a->baseAddr;
  325.     bptr = (unsigned char*) b->baseAddr;
  326.     bytecount = a->bounds.right/8;
  327.     extrabits = a->bounds.right % 8;
  328.     mask = -(1<< (8 - extrabits));
  329.     for (y=0; y< a->bounds.bottom; y++) {
  330.         arover = aptr;
  331.         brover = bptr;
  332.         for (x=0; x<bytecount; x++)
  333.             if (*arover++ != *brover++)
  334.                 return false;
  335.         if (extrabits != 0) {
  336.             if (((*arover)&mask) != ((*brover)&mask))
  337.                 return false;
  338.         }
  339.         aptr += a->rowBytes;
  340.         bptr += b->rowBytes;
  341.     }
  342.     return true;    
  343. }
  344.  
  345. /* note, we set up the portrect, the port's size, the clip region, and the
  346.     visible region all so they refer to the drawable area inside of the
  347.     bitmap pointer. */
  348. BitMapPort* NewBMP(BitMap* bits) {
  349.     BitMapPort* bmp;
  350.     Rect r;
  351.     if ((bmp = (BitMapPort*) NewPtr(sizeof(BitMapPort))) != NULL) {
  352.         r = bits->bounds;
  353.         GetPort(&bmp->gpsave);
  354.         OpenPort(&bmp->gp);
  355.         SetPortBits(bmp->bits = bits);
  356.         PortSize(r.right, r.bottom);
  357.         RectRgn(bmp->gp.visRgn, &r);
  358.         RectRgn(bmp->gp.clipRgn, &r);
  359.     }
  360.     return bmp;
  361. }
  362.  
  363. void DisposeBMP(BitMapPort* bmp) {
  364.     if (bmp != NULL) {
  365.         SetPort(bmp->gpsave);
  366.         ClosePort(&bmp->gp);
  367.         DisposePtr((Ptr) bmp);
  368.     }
  369. }
  370.  
  371. BitMap* PICTToBitMap(PicHandle pic) {
  372.     BitMap *bits;
  373.     BitMapPort* bmp;
  374.     Rect r;
  375.     r = (*pic)->picFrame;
  376.     OffsetRect(&r, -r.left, -r.top);
  377.     if ((bits = NewBitMap(r.right, r.bottom)) != NULL) {
  378.         WithBitMap(bits, bmp)
  379.             DrawPicture(pic, &r);
  380.     }
  381.     return bits;
  382. }
  383.  
  384.  
  385. void PlotBitMap(BitMap* bits, short h, short v, short mode) {
  386.     GrafPtr port;
  387.     Rect src, dst;
  388.     dst = src = bits->bounds;
  389.     OffsetRect(&dst, h, v);
  390.     GetPort(&port);
  391.     CopyBits(bits, &port->portBits, &src, &dst, mode, NULL);
  392. }
  393.  
  394. PicHandle BitMapToPICT(BitMap* bits) {
  395.     PicHandle pic;
  396.     GrafPtr saved;
  397.     GrafPort port;
  398.     Rect r;
  399.     r = bits->bounds;
  400.     GetPort(&saved);
  401.     OpenPort(&port);
  402.     ClipRect(&r);
  403.     pic = OpenPicture(&r);
  404.     PlotBitMap(bits, 0, 0, srcCopy);
  405.     ClosePicture();
  406.     SetPort(saved);
  407.     ClosePort(&port);
  408.     return pic;
  409. }
  410.  
  411. BitMap* BitMapAND(BitMap* a, BitMap* b) {
  412.     BitMap *aa, *bb, *result = NULL;
  413.     register unsigned char *ap, *bp, *rp;
  414.     long i, n;
  415.     aa = a;
  416.     bb = b;
  417.     if (EqualRect(&aa->bounds, &bb->bounds))
  418.         if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
  419.             rp = (unsigned char *) (result)->baseAddr;
  420.             ap = (unsigned char *) aa->baseAddr;
  421.             bp = (unsigned char *) bb->baseAddr;
  422.             n = (aa->rowBytes * aa->bounds.bottom);
  423.             for (i=0; i<n; i++) *rp++ = ((*ap++) & (*bp++));
  424.         }
  425.     return result;
  426. }
  427.  
  428. BitMap* BitMapOR(BitMap* a, BitMap* b) {
  429.     BitMap *aa, *bb, *result = NULL;
  430.     register unsigned char *ap, *bp, *rp;
  431.     long i, n;
  432.     aa = a;
  433.     bb = b;
  434.     if (EqualRect(&aa->bounds, &bb->bounds))
  435.         if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
  436.             rp = (unsigned char *) (result)->baseAddr;
  437.             ap = (unsigned char *) aa->baseAddr;
  438.             bp = (unsigned char *) bb->baseAddr;
  439.             n = (aa->rowBytes * aa->bounds.bottom);
  440.             for (i=0; i<n; i++) *rp++ = ((*ap++) | (*bp++));
  441.         }
  442.     return result;
  443. }
  444.  
  445. BitMap* BitMapXOR(BitMap* a, BitMap* b) {
  446.     BitMap *aa, *bb, *result = NULL;
  447.     register unsigned char *ap, *bp, *rp;
  448.     long i, n;
  449.     aa = a;
  450.     bb = b;
  451.     if (EqualRect(&aa->bounds, &bb->bounds))
  452.         if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
  453.             rp = (unsigned char *) (result)->baseAddr;
  454.             ap = (unsigned char *) aa->baseAddr;
  455.             bp = (unsigned char *) bb->baseAddr;
  456.             n = (aa->rowBytes * aa->bounds.bottom);
  457.             for (i=0; i<n; i++) *rp++ = ((*ap++) ^ (*bp++));
  458.         }
  459.     return result;
  460. }
  461.  
  462. BitMap* BitMapNOT(BitMap* a) {
  463.     BitMap *aa, *bb, *result = NULL;
  464.     register unsigned char *ap, *bp, *rp;
  465.     long i, n;
  466.     aa = a;
  467.     if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
  468.         rp = (unsigned char *) (result)->baseAddr;
  469.         ap = (unsigned char *) aa->baseAddr;
  470.         n = (aa->rowBytes * aa->bounds.bottom);
  471.         for (i=0; i<n; i++) *rp++ = ~(*ap++);
  472.     }
  473.     return result;
  474. }
  475.  
  476. Boolean BitMapTest(BitMap* bits, short h, short v) {
  477.     unsigned char* cp;
  478.     cp = (unsigned char*) (bits);
  479.     return BitTst(cp + (sizeof(BitMap) + (bits->rowBytes * v)), h);
  480. }
  481.  
  482. void BitMapSet(BitMap* bits, short h, short v) {
  483.     unsigned char* cp;
  484.     cp = (unsigned char*) (bits);
  485.     BitSet(cp + (sizeof(BitMap) + (bits->rowBytes * v)), h);
  486. }
  487.  
  488. void BitMapClear(BitMap* bits, short h, short v) {
  489.     unsigned char* cp;
  490.     cp = (unsigned char*) (bits);
  491.     BitClr(cp + (sizeof(BitMap) + (bits->rowBytes * v)), h);
  492. }
  493.  
  494. Boolean BitMapToggle(BitMap* bits, short h, short v) {
  495.     unsigned char* cp;
  496.     cp = (unsigned char*) (bits);
  497.     cp += (sizeof(BitMap) + (bits->rowBytes * v));
  498.     if (BitTst(cp, h)) {
  499.         BitClr(cp, h);
  500.         return false;
  501.     } else {
  502.         BitSet(cp, h);
  503.         return true;
  504.     }
  505. }
  506.  
  507. BitMap* StringToBitMap(short font, short size, short face, StringPtr s) {
  508.     GrafPort port;
  509.     GrafPtr saved;
  510.     FontInfo info;
  511.     BitMap *result = NULL;
  512.     GetPort(&saved);
  513.     OpenPort(&port);
  514.     TextFont(font);
  515.     TextSize(size);
  516.     TextFace(face);
  517.     GetFontInfo(&info);
  518.     if ((result = NewBitMap(StringWidth(s), info.ascent + info.descent)) != NULL) {
  519.         SetPortBits(result);
  520.         PortSize(result->bounds.right, result->bounds.bottom);
  521.         RectRgn(port.visRgn, &result->bounds);
  522.         RectRgn(port.clipRgn, &result->bounds);
  523.         MoveTo(0, info.ascent);
  524.         DrawString(s);
  525.     }
  526.     SetPort(saved);
  527.     ClosePort(&port);
  528.     return result;
  529. }
  530.  
  531. /* end File BitMap.c */
  532.  
  533.